/* * Copyright (c) LinkedIn Corporation. All rights reserved. Licensed under the BSD-2 Clause license. * See LICENSE in the project root for license information. */ package com.linkedin.mitm.proxy.connectionflow.steps; import com.linkedin.mitm.factory.CertificateKeyStoreFactory; import com.linkedin.mitm.model.CertificateAuthority; import com.linkedin.mitm.proxy.channel.ChannelMediator; import com.linkedin.mitm.services.SSLContextGenerator; import io.netty.util.concurrent.Future; import java.io.IOException; import java.net.InetSocketAddress; import java.security.InvalidKeyException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SignatureException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.ArrayList; import javax.net.ssl.SSLContext; import org.apache.log4j.Logger; import org.bouncycastle.operator.OperatorCreationException; /** * Accept client handshaking and complete handshaking using dynamically generated certificate. * * @author shfeng */ public class HandshakeWithClient implements ConnectionFlowStep { private static final String MODULE = HandshakeWithClient.class.getName(); private static final Logger LOG = Logger.getLogger(MODULE); private final CertificateKeyStoreFactory _certificateKeyStoreFactory; private final CertificateAuthority _certificateAuthority; public HandshakeWithClient(CertificateKeyStoreFactory certificateKeyStoreFactory, CertificateAuthority certificateAuthority) { _certificateKeyStoreFactory = certificateKeyStoreFactory; _certificateAuthority = certificateAuthority; } @Override public Future execute(ChannelMediator channelMediator, InetSocketAddress remoteAddress) { //dynamically create SSLEngine based on CN and SANs LOG.debug("Starting client to proxy connection handshaking"); try { //TODO: if connect request only contains ip address, we need get either CA //TODO: or SANS from server response KeyStore keyStore = _certificateKeyStoreFactory.create(remoteAddress.getHostName(), new ArrayList<>()); SSLContext sslContext = SSLContextGenerator.createClientContext(keyStore, _certificateAuthority.getPassPhrase()); return channelMediator.handshakeWithClient(sslContext.createSSLEngine()); } catch (NoSuchAlgorithmException | KeyStoreException | IOException | CertificateException | OperatorCreationException | NoSuchProviderException | InvalidKeyException | SignatureException | KeyManagementException | UnrecoverableKeyException e) { throw new RuntimeException("Failed to create server identity certificate", e); } } }